package com.koo.common.utils;

import com.alibaba.csp.sentinel.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期工具
 * @author charlin
 */
public class MyDateUtil {
    public static final String DEFAULT_DATE_FORMAT_STRING = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FROMAT_STRING = "yyyy-MM-dd HH:mm:ss";
    public static final int[] precisionArr = new int[]{1, 2, 5, 11, 12, 13, 14};
    public static final int Year = 0;
    public static final int Month = 1;
    public static final int Day_of_Month = 2;
    public static final int Hour_of_Day = 3;
    public static final int Minute = 4;
    public static final int Second = 5;
    public static final String Attd_Date_Format = "yyyyMMddHHmmss";

    public MyDateUtil() {
    }

    public final static String DATE_PATTERN = "yyyy-MM-dd";
    /** 时间格式(yyyy-MM-dd HH:mm:ss) */
    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     * @param date  日期
     * @param pattern  格式，如：DateUtils.DATE_TIME_PATTERN
     * @return  返回yyyy-MM-dd格式日期
     */
    public static String format(Date date, String pattern) {
        if(date != null){
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.format(date);
        }
        return null;
    }

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     * @param date  日期
     * @return  返回yyyy-MM-dd格式日期
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }


    /**
     * 字符串转换成日期
     * @param strDate 日期字符串
     * @param pattern 日期的格式，如：DateUtils.DATE_TIME_PATTERN
     */
    public static Date stringToDate(String strDate, String pattern) {
        if (StringUtils.isBlank(strDate)){
            return null;
        }

        DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
        return fmt.parseLocalDateTime(strDate).toDate();
    }

    /**
     * 根据周数，获取开始日期、结束日期
     * @param week  周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return  返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekStartAndEnd(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date beginDate = date.toDate();
        Date endDate = date.plusDays(6).toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 对日期的【秒】进行加/减
     *
     * @param date 日期
     * @param seconds 秒数，负数为减
     * @return 加/减几秒后的日期
     */
    public static Date addDateSeconds(Date date, int seconds) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusSeconds(seconds).toDate();
    }

    /**
     * 对日期的【分钟】进行加/减
     *
     * @param date 日期
     * @param minutes 分钟数，负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addDateMinutes(Date date, int minutes) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对日期的【小时】进行加/减
     *
     * @param date 日期
     * @param hours 小时数，负数为减
     * @return 加/减几小时后的日期
     */
    public static Date addDateHours(Date date, int hours) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusHours(hours).toDate();
    }

    /**
     * 对日期的【天】进行加/减
     *
     * @param date 日期
     * @param days 天数，负数为减
     * @return 加/减几天后的日期
     */
    public static Date addDateDays(Date date, int days) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusDays(days).toDate();
    }

    /**
     * 对日期的【周】进行加/减
     *
     * @param date 日期
     * @param weeks 周数，负数为减
     * @return 加/减几周后的日期
     */
    public static Date addDateWeeks(Date date, int weeks) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusWeeks(weeks).toDate();
    }

    /**
     * 对日期的【月】进行加/减
     *
     * @param date 日期
     * @param months 月数，负数为减
     * @return 加/减几月后的日期
     */
    public static Date addDateMonths(Date date, int months) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMonths(months).toDate();
    }

    /**
     * 对日期的【年】进行加/减
     *
     * @param date 日期
     * @param years 年数，负数为减
     * @return 加/减几年后的日期
     */
    public static Date addDateYears(Date date, int years) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusYears(years).toDate();
    }

    public static Date parseDate(Date date, String format) {
        Date returnDate = null;
        SimpleDateFormat sdf = getDateFormat(format);

        try {
            returnDate = sdf.parse(sdf.format(date));
        } catch (ParseException var5) {
            var5.printStackTrace();
        }

        return returnDate;
    }

    public static Date parseDate(Date date) {
        return parseDate(date, "yyyy-MM-dd");
    }

    public static Date parseDateTime(Date date) {
        return parseDate(date, "yyyy-MM-dd HH:mm:ss");
    }

    public static Date parseDateByDefaultFormat(String dateStr) {
        Date date = null;

        try {
            date = getDateFormat("yyyy-MM-dd").parse(dateStr);
        } catch (ParseException var3) {
            var3.printStackTrace();
        }

        return date;
    }

    public static Date parseDateTimeDefault(String dateStr) {
        Date returnDate = null;
        SimpleDateFormat sdf = getDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            returnDate = sdf.parse(dateStr);
        } catch (ParseException var4) {
            var4.printStackTrace();
        }

        return returnDate;
    }

    public static Date getCurrDate() {
        return parseDate(new Date());
    }

    public static Date getCurrDateTime() {
        return parseDate(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    public static String formatCurrDate() {
        return formatDate(new Date(), "yyyy-MM-dd");
    }

    public static String formatCurrDateTime() {
        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    public static String formatCurrDateToS(String strFormat) {
        return formatDate(new Date(), strFormat);
    }

    public static String formatDate(Date myDate) {
        return formatDate(myDate, "yyyy-MM-dd");
    }

    public static String formatDateTime(Date myDate) {
        return formatDate(myDate, "yyyy-MM-dd HH:mm:ss");
    }

    public static String formatDate(String strDate) {
        SimpleDateFormat sdf = getDateFormat("yyyy-MM-dd");
        String sDate = null;

        try {
            sDate = sdf.format(sdf.parse(strDate.trim()));
        } catch (ParseException var4) {
            var4.printStackTrace();
        }

        return sDate;
    }

    public static String formatDate(String strDate, String strFormat) throws ParseException {
        SimpleDateFormat sdf = getDateFormat(strFormat);
        String sDate = sdf.format(sdf.parse(strDate));
        return sDate;
    }

    public static String formatDate(Date myDate, String strFormat) {
        if (myDate == null) {
            return null;
        } else {
            SimpleDateFormat sdf = getDateFormat(strFormat);
            return sdf.format(myDate);
        }
    }

    public static Date getDateByDay(Date curDate, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curDate);
        calendar.add(5, -day);
        curDate = calendar.getTime();
        return curDate;
    }

    public static Date getPreviousDate(Date curDate, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curDate);
        calendar.add(5, -day);
        curDate = calendar.getTime();
        return curDate;
    }

    public static String getPreviousDateByStr(Date curDate, int day) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curDate);
        calendar.add(5, -day);
        curDate = calendar.getTime();
        return sdf.format(curDate);
    }

    public static Date getPreviousDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(5, -1);
        calendar.set(10, 0);
        calendar.set(13, 0);
        calendar.set(12, 0);
        calendar.set(14, 0);
        return getSqlDate(calendar.getTime());
    }

    public static Date parseDateByAuto(String dateStr) {
        Date date = null;
        if (StringUtil.isEmpty(dateStr)) {
            return date;
        } else {
            try {
                String format = "yyyy-MM-dd";
                if (dateStr.indexOf("/") > -1) {
                    format = format.replace("-", "/");
                }

                if (dateStr.indexOf(":") != -1) {
                    format = format + " HH:mm";
                }

                if (dateStr.indexOf(":") != dateStr.lastIndexOf(":")) {
                    format = format + ":ss";
                }

                date = getDateFormat(format).parse(dateStr);
            } catch (ParseException var3) {
                var3.printStackTrace();
            }

            return date;
        }
    }

    public static String formatDateByAuto(Date date) {
        String format = "yyyy-MM-dd";
        if (!(date instanceof java.sql.Date) && (date.getSeconds() > 0 || date.getMinutes() > 0 || date.getHours() > 0)) {
            format = "yyyy-MM-dd HH:mm:ss";
        }

        return formatDate(date, format);
    }

    public static Date parseDateTimeByDefaultFormat(String dateStr) {
        Date date = null;

        try {
            if (dateStr.indexOf(":") != -1) {
                date = getDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
            } else {
                date = getDateFormat("yyyy-MM-dd").parse(dateStr);
            }
        } catch (ParseException var3) {
            var3.printStackTrace();
        }

        return date;
    }

    private static SimpleDateFormat getDateFormat(String strFormat) {
        SimpleDateFormat sdf = new SimpleDateFormat(strFormat);
        return sdf;
    }

    public static int compareDate(Date date1, Date date2) {
        int y = date1.getYear() - date2.getYear();
        if (y == 0) {
            int m = date1.getMonth() - date2.getMonth();
            return m == 0 ? date1.getDate() - date2.getDate() : m;
        } else {
            return y;
        }
    }

    public static String formatDateByApm(Date date, Integer[] apm) {
        if (apm != null && apm.length != 0 && apm[0] != null) {
            return apm[0] == 0 ? formatDate(date, "yyyy-MM-dd") + " 上午" : formatDate(date, "yyyy-MM-dd") + " 下午";
        } else {
            return formatDate(date, "yyyy-MM-dd HH:mm");
        }
    }

    public static Date parseDateByFormat(String dateStr, String strFormat) {
        SimpleDateFormat sdf = new SimpleDateFormat(strFormat);
        Date date = null;
        if (StringUtil.isNotEmpty(dateStr)) {
            try {
                date = sdf.parse(dateStr);
            } catch (ParseException var5) {
                var5.printStackTrace();
            }
        }

        return date;
    }

    public static Calendar parseDateTime(String baseDate) {
        Calendar cal = new GregorianCalendar();
        int yy = Integer.parseInt(baseDate.substring(0, 4));
        int mm = Integer.parseInt(baseDate.substring(5, 7)) - 1;
        int dd = Integer.parseInt(baseDate.substring(8, 10));
        int hh = 0;
        int mi = 0;
        int ss = 0;
        if (baseDate.length() > 12) {
            hh = Integer.parseInt(baseDate.substring(11, 13));
        }

        if (baseDate.length() > 15) {
            mi = Integer.parseInt(baseDate.substring(14, 16));
        }

        if (baseDate.length() > 18) {
            ss = Integer.parseInt(baseDate.substring(17, 19));
        }

        cal.set(yy, mm, dd, hh, mi, ss);
        cal.set(14, 0);
        return cal;
    }

    public static Calendar parseDateTimeToC(Date baseDate, int hh, int mi, int ss) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(baseDate);
        cal.set(11, hh);
        cal.set(12, mi);
        cal.set(13, ss);
        cal.set(14, 0);
        return cal;
    }

    public static Date parseDateTimeToD(Date baseDate, int hh, int mi, int ss) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(baseDate);
        cal.set(11, hh);
        cal.set(12, mi);
        cal.set(13, ss);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date convDateTimeToDate(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(11, 0);
        cal.set(12, 0);
        cal.set(13, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static String convDateToYM(Date date) {
        return formatDate(date, "yyyyMM");
    }

    public static Date convYMToMonFirst(String yearMonth) {
        Calendar cal = new GregorianCalendar();
        int year = Integer.valueOf(yearMonth.substring(0, 4));
        int month = Integer.valueOf(yearMonth.substring(4));
        cal.set(year, month - 1, 1, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date convYMToNextMonFirst(String yearMonth) {
        Calendar cal = new GregorianCalendar();
        int year = Integer.valueOf(yearMonth.substring(0, 4));
        int month = Integer.valueOf(yearMonth.substring(4));
        cal.set(year, month, 1, 0, 0, 0);
        return cal.getTime();
    }

    public static Date convYMToMonEnd(String yearMonth) {
        Calendar cal = new GregorianCalendar();
        int year = Integer.valueOf(yearMonth.substring(0, 4));
        int month = Integer.valueOf(yearMonth.substring(4));
        cal.set(year, month, 0, 0, 0, 0);
        return cal.getTime();
    }

    public static String yearMonthAdd(String yearMonth, int iCount, int iType) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(convYMToMonFirst(yearMonth));
        cal.add(iType, iCount);
        return convDateToYM(cal.getTime());
    }

    public static Calendar convDateTimeToDateCal(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(11, 0);
        cal.set(12, 0);
        cal.set(13, 0);
        cal.set(14, 0);
        return cal;
    }

    public static int getYear(String strDate) {
        Calendar cal = parseDateTime(strDate);
        return cal.get(1);
    }

    public static int getYear(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return c.get(1);
    }

    public static int getMonth(String strDate) {
        Calendar cal = parseDateTime(strDate);
        return cal.get(2) + 1;
    }

    public static int getMonth(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return c.get(2) + 1;
    }

    public static int getDay(String strDate) {
        Calendar cal = parseDateTime(strDate);
        return cal.get(5);
    }

    public static int getDay(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return c.get(5);
    }

    public static int getHour(String strDate) {
        Calendar cal = parseDateTime(strDate);
        return cal.get(11);
    }

    public static int getHour(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return c.get(11);
    }

    public static int getMinute(String strDate) {
        Calendar cal = parseDateTime(strDate);
        return cal.get(12);
    }

    public static int getMinute(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return c.get(12);
    }

    public static int getWeekDay(String strDate) {
        Calendar cal = parseDateTime(strDate);
        return cal.get(7);
    }

    public static int getWeekDay(Date date) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        return c.get(7);
    }

    public static String getWeekDayName(String strDate) {
        String[] mName = new String[]{"日", "一", "二", "三", "四", "五", "六"};
        int iWeek = getWeekDay(strDate);
        --iWeek;
        return "星期" + mName[iWeek];
    }

    public static String getWeekDayName(Date date) {
        String[] mName = new String[]{"日", "一", "二", "三", "四", "五", "六"};
        int iWeek = getWeekDay(date);
        --iWeek;
        return "星期" + mName[iWeek];
    }

    public static String dateTimeAdd(String strDate, int iCount, int iType) {
        Calendar cal = parseDateTime(strDate);
        cal.add(iType, iCount);
        SimpleDateFormat sdf = null;
        if (iType != 1 && iType != 2 && iType != 5) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        } else {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }

        String sDate = sdf.format(cal.getTime());
        return sDate;
    }

    public static Date dateTimeAdd(Date date, int iCount, int iType) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(iType, iCount);
        return cal.getTime();
    }

    public static Date dateAdd(Date date, int iCount) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(5, iCount);
        return cal.getTime();
    }

    public static int dateDiff(String strDateBegin, String strDateEnd, int iType) {
        Calendar calBegin = parseDateTime(strDateBegin);
        Calendar calEnd = parseDateTime(strDateEnd);
        long lBegin = calBegin.getTimeInMillis();
        long lEnd = calEnd.getTimeInMillis();
        if (iType == 13) {
            return (int) ((lEnd - lBegin) / 1000L);
        } else if (iType == 12) {
            return (int) ((lEnd - lBegin) / 60000L);
        } else if (iType == 10) {
            return (int) ((lEnd - lBegin) / 3600000L);
        } else {
            return iType == 5 ? (int) ((lEnd - lBegin) / 86400000L) : -1;
        }
    }

    public static BigDecimal hourDiff(Date dateBegin, Date dateEnd) {
        Calendar calBegin = new GregorianCalendar();
        calBegin.setTime(dateBegin);
        Calendar calEnd = new GregorianCalendar();
        calEnd.setTime(dateEnd);
        long lBegin = calBegin.getTimeInMillis();
        long lEnd = calEnd.getTimeInMillis();
        return BigDecimal.valueOf(lEnd - lBegin).divide(BigDecimal.valueOf(3600000L), 2, RoundingMode.HALF_UP);
    }

    public static int dateDiff(Date dateBegin, Date dateEnd, int iType) {
        Calendar calBegin = new GregorianCalendar();
        calBegin.setTime(dateBegin);
        Calendar calEnd = new GregorianCalendar();
        calEnd.setTime(dateEnd);
        long lBegin = calBegin.getTimeInMillis();
        long lEnd = calEnd.getTimeInMillis();
        if (iType == 13) {
            return (int) ((lEnd - lBegin) / 1000L);
        } else if (iType == 12) {
            return (int) ((lEnd - lBegin) / 60000L);
        } else if (iType == 10) {
            return (int) ((lEnd - lBegin) / 3600000L);
        } else {
            return iType == 5 ? (int) ((lEnd - lBegin) / 86400000L) : -1;
        }
    }

    public static long dateDiff(Date start, Date end) {
        start = (Date) start.clone();
        end = (Date) end.clone();
        start.setHours(0);
        start.setMinutes(0);
        start.setSeconds(0);
        end.setHours(0);
        end.setMinutes(0);
        end.setSeconds(0);
        return (end.getTime() - start.getTime()) / 86400000L;
    }

    public static boolean isDateRemind(Date dateToRemind, Date dateCurrent, int days, int cMode) {
        int yearDiffRate;
        if (cMode <= -1) {
            yearDiffRate = dateDiff((Date) dateCurrent, (Date) dateToRemind, 5);
            return yearDiffRate <= days;
        } else if (cMode == 0) {
            yearDiffRate = dateDiff((Date) dateCurrent, (Date) dateToRemind, 5);
            return yearDiffRate <= days && yearDiffRate >= 0;
        } else {
            yearDiffRate = (getYear(dateCurrent) - getYear(dateToRemind)) / cMode;
            Date newDateToRemind = dateTimeAdd((Date) dateToRemind, yearDiffRate * cMode, 1);
            if (dateDiff((Date) newDateToRemind, (Date) dateCurrent, 5) > 0) {
                newDateToRemind = dateTimeAdd((Date) newDateToRemind, cMode, 1);
            }

            int dayDiff = dateDiff((Date) dateCurrent, (Date) newDateToRemind, 5);
            return dayDiff <= days && dayDiff >= 0;
        }
    }

    public static boolean isLeapYear(int yearNum) {
        boolean isLeep = false;
        if (yearNum % 4 == 0 && yearNum % 100 != 0) {
            isLeep = true;
        } else if (yearNum % 400 == 0) {
            isLeep = true;
        } else {
            isLeep = false;
        }

        return isLeep;
    }

    public static int getWeekNumOfYear() {
        Calendar calendar = Calendar.getInstance();
        int iWeekNum = calendar.get(3);
        return iWeekNum;
    }

    public static int getWeekNumOfYearDay(String strDate) throws ParseException {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date curDate = format.parse(strDate);
        calendar.setTime(curDate);
        int iWeekNum = calendar.get(3);
        return iWeekNum;
    }

    public static int getWeekNumOfYearDay(Date date) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        int iWeekNum = calendar.get(3);
        return iWeekNum;
    }

    public static String getYearWeekFirstDay(int yearNum, int weekNum) throws ParseException {
        Calendar cal = Calendar.getInstance();
        cal.set(1, yearNum);
        cal.set(3, weekNum);
        cal.set(7, 2);
        String tempYear = Integer.toString(yearNum);
        String tempMonth = Integer.toString(cal.get(2) + 1);
        String tempDay = Integer.toString(cal.get(5));
        String tempDate = tempYear + "-" + tempMonth + "-" + tempDay;
        return formatDate(tempDate, "yyyy-MM-dd");
    }

    public static String getYearWeekEndDay(int yearNum, int weekNum) throws ParseException {
        Calendar cal = Calendar.getInstance();
        cal.set(1, yearNum);
        cal.set(3, weekNum + 1);
        cal.set(7, 1);
        String tempYear = Integer.toString(yearNum);
        String tempMonth = Integer.toString(cal.get(2) + 1);
        String tempDay = Integer.toString(cal.get(5));
        String tempDate = tempYear + "-" + tempMonth + "-" + tempDay;
        return formatDate(tempDate, "yyyy-MM-dd");
    }

    public static Date getYearMonthFirstDay(int yearNum, int monthNum) {
        Calendar cal = new GregorianCalendar();
        cal.set(yearNum, monthNum - 1, 1, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getNextYearMonthFirstDay(int yearNum, int monthNum) {
        Calendar cal = new GregorianCalendar();
        cal.set(yearNum, monthNum, 1, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getYearMonthEndDay(int yearNum, int monthNum) {
        Calendar cal = new GregorianCalendar();
        cal.set(yearNum, monthNum, 0, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getYearMonthFirstDay(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(5, 1);
        cal.set(11, 0);
        cal.set(12, 0);
        cal.set(13, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getNextYearMonthFirstDay(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(2, 1);
        cal.set(5, 1);
        cal.set(11, 0);
        cal.set(12, 0);
        cal.set(13, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getYearMonthEndDay(Date date) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(5, cal.getActualMaximum(5));
        cal.set(11, 0);
        cal.set(12, 0);
        cal.set(13, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getYearFirstDay(int yearNum) {
        Calendar cal = new GregorianCalendar();
        cal.set(yearNum, 0, 1, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getNextYearFirstDay(int yearNum) {
        Calendar cal = new GregorianCalendar();
        cal.set(yearNum, 12, 1, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static Date getYearEndDay(int yearNum) {
        Calendar cal = new GregorianCalendar();
        cal.set(yearNum, 12, 0, 0, 0, 0);
        cal.set(14, 0);
        return cal.getTime();
    }

    public static String getWeek(String strDate, int weekNum) {
        Calendar c = parseDateTime(strDate);
        if (weekNum == 1) {
            c.set(7, 2);
        } else if (weekNum == 2) {
            c.set(7, 3);
        } else if (weekNum == 3) {
            c.set(7, 4);
        } else if (weekNum == 4) {
            c.set(7, 5);
        } else if (weekNum == 5) {
            c.set(7, 6);
        } else if (weekNum == 6) {
            c.set(7, 7);
        } else if (weekNum == 0) {
            c.set(7, 1);
        }

        return (new SimpleDateFormat("yyyy-MM-dd")).format(c.getTime());
    }

    public static Date getWeek(Date date, int weekNum) {
        Calendar c = new GregorianCalendar();
        c.setTime(date);
        if (weekNum == 1) {
            c.set(7, 2);
        } else if (weekNum == 2) {
            c.set(7, 3);
        } else if (weekNum == 3) {
            c.set(7, 4);
        } else if (weekNum == 4) {
            c.set(7, 5);
        } else if (weekNum == 5) {
            c.set(7, 6);
        } else if (weekNum == 6) {
            c.set(7, 7);
        } else if (weekNum == 0) {
            c.set(7, 1);
        }

        return c.getTime();
    }

    public static int getDaysBetween(Date startDate, Date endDate) {
        new GregorianCalendar();
        Calendar d1 = convDateTimeToDateCal(startDate);
        new GregorianCalendar();
        Calendar d2 = convDateTimeToDateCal(endDate);
        if (d1.after(d2)) {
            Calendar swap = d1;
            d1 = d2;
            d2 = swap;
        }

        int days = d2.get(6) - d1.get(6);
        int y2 = d2.get(1);
        if (d1.get(1) != y2) {
            d1 = (Calendar) d1.clone();

            do {
                days += d1.getActualMaximum(6);
                d1.add(1, 1);
            } while (d1.get(1) != y2);
        }

        return days;
    }

    public static Date getNextMonday(Date date) {
        Calendar result = new GregorianCalendar();
        result.setTime(date);

        do {
            result.add(5, 1);
        } while (result.get(7) != 2);

        return result.getTime();
    }

    public static int getWorkingDay(Date startDate, Date endDate) {
        if (startDate.after(endDate)) {
            Date swap = startDate;
            startDate = endDate;
            endDate = swap;
        }

        int actualDays = dateDiff((Date) startDate, (Date) endDate, 5) + 1;
        int weekDays = actualDays / 7 * 5;
        startDate = dateAdd(startDate, actualDays / 7 * 7);
        int count = 0;
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(startDate);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(endDate);

        for (int i = 0; !cal1.after(cal2); ++i) {
            if (cal1.get(7) != 7 && cal1.get(7) != 1) {
                ++count;
            }

            cal1.add(5, 1);
        }

        return weekDays + count;
    }

    public static int compareTwoDay(Date date1, Date date2) {
        if (date1 != null && date2 != null) {
            date1 = convDateTimeToDate(date1);
            date2 = convDateTimeToDate(date2);
            if (date1.compareTo(date2) < 0) {
                return 1;
            } else {
                return date1.compareTo(date2) == 0 ? 0 : -1;
            }
        } else {
            return -2;
        }
    }

    public static Calendar getFirstDayInMonth(Calendar now) {
        Calendar tmp = (Calendar) now.clone();
        int day = tmp.get(5);
        tmp.add(5, 1 - day);
        return tmp;
    }

    public static Calendar getFirstDayInQuartz(Calendar now) {
        Calendar tmp = (Calendar) now.clone();
        int day = tmp.get(5);
        tmp.add(5, 1 - day);
        int month = tmp.get(2);
        tmp.add(2, 0 - month % 3);
        return tmp;
    }

    public static Calendar getFirstDayInHalfYear(Calendar now) {
        Calendar tmp = (Calendar) now.clone();
        int day = tmp.get(5);
        tmp.add(5, 1 - day);
        int month = tmp.get(2);
        tmp.add(2, 0 - month % 6);
        return tmp;
    }

    public static Calendar getFirstDayInYear(Calendar now) {
        Calendar tmp = (Calendar) now.clone();
        int day = tmp.get(5);
        tmp.add(5, 1 - day);
        tmp.set(2, 0);
        return tmp;
    }

    public static Calendar getLastDayInMonth(Calendar now) {
        Calendar tmp = (Calendar) now.clone();
        tmp.set(5, tmp.getActualMaximum(5));
        return tmp;
    }

    public static Calendar getLastDayInQuartz(Calendar now) {
        Calendar tmp = getFirstDayInQuartz(now);
        tmp.add(2, 3);
        tmp.add(5, -1);
        return tmp;
    }

    public static Calendar getLastDayInHalfYear(Calendar now) {
        Calendar tmp = getFirstDayInHalfYear(now);
        tmp.add(2, 6);
        tmp.add(5, -1);
        return tmp;
    }

    public static Calendar getLastDayInYear(Calendar now) {
        Calendar tmp = getFirstDayInYear(now);
        tmp.add(2, 12);
        tmp.add(5, -1);
        return tmp;
    }

    public static boolean hasConflict(List<Date> dList1, List<Date> dList2) {
        int length1 = dList1.size();
        int length2 = dList2.size();
        if (length1 != 0 && length2 != 0) {
            int p1 = 0;
            int p2 = 0;
            Date d11 = (Date) dList1.get(p1++);
            Date d12 = (Date) dList1.get(p1++);
            Date d21 = (Date) dList2.get(p2++);
            Date d22 = (Date) dList2.get(p2++);

            while (true) {
                while (true) {
                    int result = hasConflict(d11, d12, d21, d22);
                    if (result == -1) {
                        if (p1 >= length1) {
                            return true;
                        }

                        d11 = (Date) dList1.get(p1++);
                        d12 = (Date) dList1.get(p1++);
                    } else {
                        if (result != 1) {
                            return false;
                        }

                        if (p2 >= length2) {
                            return true;
                        }

                        d21 = (Date) dList2.get(p2++);
                        d22 = (Date) dList2.get(p2++);
                    }
                }
            }
        } else {
            return true;
        }
    }

    public static int hasConflict(List<Date> dList1, Date dateBgn, Date dateEnd) {
        int length1 = dList1.size();
        if (length1 == 0) {
            return 0;
        } else {
            int i = 0;

            Date d1;
            Date d2;
            int result;
            do {
                if (i >= length1) {
                    return 0;
                }

                d1 = (Date) dList1.get(i++);
                d2 = (Date) dList1.get(i++);
                result = hasConflict(dateBgn, dateEnd, d1, d2);
                if (result == -1) {
                    return 0;
                }
            } while (result != 0);

            if (isEqual(dateBgn, d1) && isEqual(dateEnd, d2)) {
                return 1;
            } else {
                return -1;
            }
        }
    }

    public static int addDate(List<Date> dList1, Date dateBgn, Date dateEnd) {
        int length1 = dList1.size();
        int i = 0;

        Date d1;
        Date d2;
        int result;
        do {
            if (i >= length1) {
                dList1.add(dateBgn);
                dList1.add(dateEnd);
                return length1;
            }

            d1 = (Date) dList1.get(i++);
            d2 = (Date) dList1.get(i++);
            result = hasConflict(dateBgn, dateEnd, d1, d2);
            if (result == -1) {
                i -= 2;
                dList1.add(i, dateEnd);
                dList1.add(i, dateBgn);
                return i;
            }
        } while (result != 0);

        if (isEqual(dateBgn, d1) && isEqual(dateEnd, d2)) {
            return -2;
        } else {
            return -1;
        }
    }

    public static int hasConflict(Date d1Bgn, Date d1End, Date d2Bgn, Date d2End) {
        if (compareTwoDay(d1Bgn, d2End) == -1) {
            return 1;
        } else {
            return compareTwoDay(d2Bgn, d1End) == -1 ? -1 : 0;
        }
    }

    public static List<Date> getIntervalByMonth(Date startDate, Date endDate) {
        if (startDate.compareTo(endDate) > 0) {
            return null;
        } else {
            List dateList = new ArrayList();
            Calendar start = new GregorianCalendar();
            start.setTime(startDate);
            start = formatCalendar(start, "0");
            Calendar end = new GregorianCalendar();
            end.setTime(endDate);
            end = formatCalendar(end, "0");
            while (start.compareTo(end) <= 0) {
                dateList.add(start.getTime());
                start.set(2, start.get(2) + 1);
            }
            return dateList;
        }
    }

    public static List<Date> getIntervalByYear(Date startDate, Date endDate) {
        if (startDate.compareTo(endDate) > 0) {
            return null;
        } else {
            List dateList = new ArrayList();
            Calendar start = new GregorianCalendar();
            start.setTime(startDate);
            start = formatCalendar(start, "1");
            Calendar end = new GregorianCalendar();
            end.setTime(endDate);
            end = formatCalendar(end, "1");

            while (start.compareTo(end) <= 0) {
                dateList.add(start.getTime());
                start.set(1, start.get(1) + 1);
            }

            return dateList;
        }
    }

    public static Calendar formatCalendar(Calendar cal, String format) {
        if (cal == null) {
            return null;
        } else {
            cal.set(11, 0);
            cal.set(12, 0);
            cal.set(13, 0);
            cal.set(14, 0);
            if (format.equals("0")) {
                cal.set(5, 1);
            } else if (format.equals("1")) {
                cal.set(5, 1);
                cal.set(2, 0);
            }

            return cal;
        }
    }

    private static boolean isEqual(Date d1, Date d2) {
        if (d1 == null && d2 == null) {
            return true;
        } else {
            return compareTwoDay(d1, d2) == 0;
        }
    }

    public static Date getAddMonth(Date date, int n) {
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.add(2, n);
        return gc.getTime();
    }

    public static Date getAddDay(Date date, int n) {
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        gc.add(5, n);
        return gc.getTime();
    }

    public static Date getSqlDate(Date date) {
        return new Date(date.getTime());
    }

    public static Date getLastDayOfMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(1, year);
        calendar.set(2, month);
        calendar.set(5, 1);
        return getPreviousDate(getSqlDate(calendar.getTime()));
    }

    public static int getDaysInMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(1, year);
        cal.set(2, month - 1);
        return cal.getActualMaximum(5);
    }

    public static int getAgeByBirthday(Date birthday) {
        Calendar cal = Calendar.getInstance();
        if (cal.before(birthday)) {
            throw new IllegalArgumentException("The birthDay is before Now.It's unbelievable!");
        } else {
            int yearNow = cal.get(1);
            int monthNow = cal.get(2) + 1;
            int dayOfMonthNow = cal.get(5);
            cal.setTime(birthday);
            int yearBirth = cal.get(1);
            int monthBirth = cal.get(2) + 1;
            int dayOfMonthBirth = cal.get(5);
            int age = yearNow - yearBirth;
            if (monthNow <= monthBirth) {
                if (monthNow == monthBirth) {
                    if (dayOfMonthNow < dayOfMonthBirth) {
                        --age;
                    }
                } else {
                    --age;
                }
            }

            return age;
        }
    }

    public static int getDaysInMonth(Date date1, Date date2, String yearMonth) {
        int year = Integer.parseInt(yearMonth.substring(0, 4));
        int month = Integer.parseInt(yearMonth.substring(4));
        if (!date1.after(getYearMonthEndDay(year, month)) && (null == date2 || !date2.before(getYearMonthFirstDay(year, month)))) {
            date1 = date1.before(getYearMonthFirstDay(year, month)) ? getYearMonthFirstDay(year, month) : date1;
            date2 = date2 != null && !date2.after(getYearMonthEndDay(2014, 7)) ? date2 : getYearMonthEndDay(year, month);
            return getDaysBetween(date1, date2) + 1;
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        String s = null;
        System.out.println(getPreviousDate(new Date(), 3));
    }
}
